/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Model;

import Actors.Actor;
import Actors.CollisionType;
import java.util.Vector;

/**
 *
 * @author Snowangelic
 */
public class Plateau implements ActorManagerListener, ActorListener,InventoryListener {
    EnigmaModel model;
    Case[][] plane;

    Vector<PlateauListener> listeners;
    Vector<CollisionListener> collisionListeners;

    Plateau(EnigmaModel model){
        this.model=model;
        listeners=new Vector<PlateauListener>();
        collisionListeners=new Vector<CollisionListener>();
    }

    void addListener(PlateauListener listener){
        if(!listeners.contains(listener))
            listeners.add(listener);
    }

    void removeListener(PlateauListener listener){
        listeners.remove(listener);
    }

        public void addCollisionListener(CollisionListener listener){
        if(!collisionListeners.contains(listener))
                collisionListeners.add(listener);
    }

    public double[] getImpulse(Actor actor) {
        double[] impulse=new double[2];
        impulse[0]=0;
        impulse[1]=0;
        for(int i=0;i<plane.length;i++)
            for(int j=0;j<plane[0].length;j++){
                    double[] tempImpulse=plane[i][j].getImpulse(actor);
                    impulse[0]=impulse[0]+tempImpulse[0];
                    impulse[1]=impulse[1]+tempImpulse[1];
                }
        return impulse;
    }

    int getWidth() {
        return plane.length;
    }

    int getHeight() {
        return plane[0].length;
    }

    EnigmaModel getModel(){
        return model;
    }

    public void clear(){
        plane=new Case[1][1];
    }

    public void setPlaneDimension(int width,int height){
        plane=new Case[width][height];

        for(PlateauListener listener : listeners){
            listener.dimensionSet(width,height);
        }
    }

    public void addCase(Case myCase){
        int x=myCase.getXIndex();
        int y=myCase.getYIndex();

        if(x<plane.length && y<plane[0].length){
            plane[x][y]=myCase;
            for(PlateauListener listener : listeners)
                listener.caseAdded(new CaseEvent(myCase));
        }
    }

    /*
    public void generateLevel() {
        setPlaneDimension(20,15);
        //Case Wall=new Case(this,floor,mur,null);
        //Case Sol=new Case(this,floor,null,null);

        for(int i=0;i<plane.length;i++)
            for(int j=0;j<plane[0].length;j++){
                System.out.println("Case : "+i+" , "+j+"");
                Stones.Stone mur=new Stones.WallStone();
                Floors.Floor floor=new Floors.BasicFloor();
                Floors.Floor water=new Floors.WaterFloor();
                if(i==0||j==0) addCase(new Case(this,i,j,floor,mur,null));
                else if(i==19)addCase(new Case(this,i,j,floor,mur,null));
                else if(j==12)addCase(new Case(this,i,j,floor,mur,null));
                else if(j==8) addCase(new Case(this,i,j,water,null,null));
                //else if(i==7 && j==7)plane[i][j]=new Case(this,7,7,floor,mur,null);
                else addCase(new Case(this,i,j,floor,null,null));
                
            }
        Floors.Floor floor1=new Floors.BasicFloor();
        Floors.Floor floor2=new Floors.BasicFloor();
        Floors.Floor floor3=new Floors.BasicFloor();
        Floors.Floor floor4=new Floors.BasicFloor();
        Floors.Floor floor5=new Floors.BasicFloor();
        Floors.Floor floor6=new Floors.BasicFloor();
        Floors.Floor floor7=new Floors.BasicFloor();
        Floors.Floor floor8=new Floors.BasicFloor();
        Floors.Floor floor9=new Floors.BasicFloor();

        Items.Item blackbomb1 = new Items.BlackBomb();
        Items.Item blackbomb2 = new Items.BlackBomb();
        Items.Item whitebomb = new Items.WhiteBomb();
        Items.Item whitebomb2 = new Items.WhiteBomb();



        addCase(new Case(this,0,3,floor,new Oxyde(1),null));
        addCase(new Case(this,3,4,floor,new Oxyde(1),null));



        addCase(new Case(this,10,3,floor,new Oxyde(2),null));
        addCase(new Case(this,10,4,floor,new Oxyde(2),null));

    }
     * */

    void actorCollidesWith(Actor actor, int xIndex, int yIndex, CollisionType collisionType) {
        if(xIndex>=0 && xIndex<plane.length && yIndex>=0 && yIndex<plane[0].length){
            if(collisionType==CollisionType.Up) plane[xIndex][yIndex].upCollision(actor);
            else if(collisionType==CollisionType.Down) plane[xIndex][yIndex].downCollision(actor);
            else if(collisionType==CollisionType.Left) plane[xIndex][yIndex].leftCollision(actor);
            else if(collisionType==CollisionType.Right) plane[xIndex][yIndex].rightCollision(actor);
            /*
            else if(collisionType==CollisionType.UpLeft) plane[xIndex][yIndex].upLeftCollision(actor);
            else if(collisionType==CollisionType.UpRight) plane[xIndex][yIndex].upRightCollision(actor);
            else if(collisionType==CollisionType.DownLeft) plane[xIndex][yIndex].downLeftCollision(actor);
            else if(collisionType==CollisionType.DownRight) plane[xIndex][yIndex].downRightCollision(actor);
             * */

            for(CollisionListener listener : collisionListeners)
                listener.collision(new CollisionEvent(actor,plane[xIndex][yIndex],collisionType));
        }
    }

    void updateFloors(long dtime) {
        for(int i=0;i<plane.length;i++)
          for(int j=0;j<plane[0].length;j++)
              plane[i][j].updateFloor(dtime);
    }

    void updateStones(long dtime) {
        for(int i=0;i<plane.length;i++)
          for(int j=0;j<plane[0].length;j++)
              plane[i][j].updateStone(dtime);
    }

    void updateItems(long dtime) {
        for(int i=0;i<plane.length;i++)
          for(int j=0;j<plane[0].length;j++)
              plane[i][j].updateItem(dtime);
    }

    public double getFriction(int xIndex,int yIndex){
        if(xIndex>0 && xIndex<plane.length && yIndex>0 && yIndex<plane[0].length)
            return plane[xIndex][yIndex].getFriction();
        else return 100;
    }

    void actorEntersCase(Actor actor, int xIndex, int yIndex) {
        if(xIndex>=0 && xIndex<plane.length && yIndex>=0 && yIndex<plane[0].length)
            plane[xIndex][yIndex].actorEnters(actor);
    }

    void actorLeavesCase(Actor actor, int xIndex, int yIndex) {
        if(xIndex>=0 && xIndex<plane.length && yIndex>=0 && yIndex<plane[0].length)
            plane[xIndex][yIndex].actorLeaves(actor);
    }

    public Case getCase(int xIndex, int yIndex){
        if(xIndex>=0 && xIndex<plane.length && yIndex>=0 && yIndex<plane[0].length)
            return plane[xIndex][yIndex];
        else return null;
    }

    public void actorAdded(ActorEvent actorEvent) {
        actorEvent.getSource().addListener(this);
    }

    public void actorMoved(ActorEvent e) {
        Actor actor=e.getSource();

        // Si l'actor change de case
        if(actor.getXIndex()!=actor.getOldXIndex() || actor.getYIndex()!=actor.getOldYIndex()){
            if(actor.getXIndex()>=0 && actor.getXIndex() < plane.length
                    && actor.getYIndex()>=0 && actor.getYIndex() < plane[0].length){
            actor.setFriction(getFriction(actor.getXIndex(),actor.getYIndex()));
            plane[actor.getOldXIndex()][actor.getOldYIndex()].actorLeaves(actor);
            plane[actor.getXIndex()][actor.getYIndex()].actorEnters(actor);
            }
        }

        // Vérification des collisions
        //--- Gestion des collsions avec les Cases ---
            int xIndex=e.getSource().getXIndex();
            int yIndex=e.getSource().getYIndex();

            //if(actorDoesCollideWith(actor,xIndex-1,yIndex-1,CollisionType.DownRight)){
            //    actorCollidesWith(actor,xIndex-1,yIndex-1,CollisionType.DownRight);
            //}

            if(actorDoesCollideWith(actor,xIndex,yIndex-1,CollisionType.Down)){
                actorCollidesWith(actor,xIndex,yIndex-1,CollisionType.Down);
            }

            //if(actorDoesCollideWith(actor,xIndex+1,yIndex-1,CollisionType.DownLeft)){
            //    actorCollidesWith(actor,xIndex+1,yIndex,CollisionType.DownLeft);
            //}

            if(actorDoesCollideWith(actor,xIndex-1,yIndex,CollisionType.Right)){
                actorCollidesWith(actor,xIndex-1,yIndex,CollisionType.Right);
            }

            if(actorDoesCollideWith(actor,xIndex+1,yIndex,CollisionType.Left)){
                actorCollidesWith(actor,xIndex+1,yIndex,CollisionType.Left);

            }

            //if(actorDoesCollideWith(actor,xIndex-1,yIndex+1,CollisionType.UpRight))
            //    actorCollidesWith(actor,xIndex-1,yIndex+1,CollisionType.UpRight);

            if(actorDoesCollideWith(actor,xIndex,yIndex+1,CollisionType.Up)){
                actorCollidesWith(actor,xIndex,yIndex+1,CollisionType.Up);
            }

            //if(actorDoesCollideWith(actor,xIndex+1,yIndex+1,CollisionType.UpLeft))
            //    actorCollidesWith(actor,xIndex+1,yIndex+1,CollisionType.UpLeft);

    }

    private boolean actorDoesCollideWith(Actor actor,int xIndex,int yIndex,CollisionType type){
        int yPos=actor.getY();
        int xPos=actor.getX();
        int rayon=actor.getRayon();

        // Vérfication d'une collision Depuis le bas
        if(type==CollisionType.Down)
            if(yPos-rayon<((yIndex+1)*32))
                return true;
            else return false;

        //Vérification d'une collision depuis le haut
        if(type==CollisionType.Up)
            if(yPos+rayon>=((yIndex)*32))
                return true;
            else return false;

        //Vérification d'une collision depuis la droite
        if(type==CollisionType.Right)
            if(xPos-rayon<((xIndex+1)*32))
                return true;
            else return false;

        //Vérification d'une collision depuis la gauche
        if(type==CollisionType.Left)
            if((xPos+rayon)>=((xIndex)*32))
                return true;
            else return false;

        //Vérification d'une collision sur les coins
        /*
        if(type==CollisionType.DownLeft || type==CollisionType.DownRight ||
                type==CollisionType.UpLeft || type==CollisionType.UpRight){
            double dist=distToCase(xIndex,yIndex);
            if(dist<((Math.sqrt(2)*16)+rayon)-1)
                return true;
            else return false;

        }
         * */

        else return false;
    }

    public void inventoryUpdated(InventoryEvent e) {
    }

    public void itemDropped(ItemDroppedEvent e) {
        //System.out.println("Adding Item");
        if(plane[e.getXIndex()][e.getYIndex()].getItem()==null)
            plane[e.getXIndex()][e.getYIndex()].addItem(e.getSource());

        else e.getSource().goToInventory();
    }

    public void actorDied(ActorEvent e) {

    }

    public void itemUsed(ItemUsedEvent e) {
    }

    public void actorImageChanged(ActorEvent e) {
    }

    /*
    private double distToCase(int xIndex, int yIndex) {
        double xDist=xPos-((xIndex*32)+16);
        double yDist=yPos-((yIndex*32)+16);
        return Math.sqrt((xDist*xDist)+(yDist*yDist));
    }
     * */
}
